package com.zenithmind.disk.pojo.dto;

import io.swagger.v3.oas.annotations.media.Schema;
import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.Size;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.apache.commons.lang3.StringUtils;

/**
 * 文件信息传输对象
 * 遵循单一职责原则：专注于文件数据传输
 * 遵循开闭原则：通过枚举和验证方法便于扩展
 */
@Data
@AllArgsConstructor
@NoArgsConstructor
@Schema(description = "文件信息DTO")
public class FileDTO {

    @Schema(description = "文件ID")
    private String id;

    @NotBlank(message = "用户ID不能为空")
    @Schema(description = "用户ID")
    private String userId;

    @Schema(description = "父级目录ID，null表示根目录")
    private String parentId;

    @NotBlank(message = "文件名不能为空")
    @Size(max = 255, message = "文件名长度不能超过255个字符")
    @Schema(description = "文件名")
    private String fileName;

    @Schema(description = "文件类型")
    private String fileType;

    @Schema(description = "是否为目录")
    private Boolean isDirectory;

    @Schema(description = "是否加密")
    private Integer isEncrypted;

    @Size(max = 50, message = "加密密码长度不能超过50个字符")
    @Schema(description = "加密密码")
    private String encryptPassword;

    // ==================== 业务方法 ====================

    /**
     * 检查是否为目录
     * @return true如果是目录
     */
    public boolean isDirectoryType() {
        return Boolean.TRUE.equals(isDirectory);
    }

    /**
     * 检查是否为文件
     * @return true如果是文件
     */
    public boolean isFileType() {
        return !isDirectoryType();
    }

    /**
     * 检查是否在根目录
     * @return true如果在根目录
     */
    public boolean isInRootDirectory() {
        return StringUtils.isBlank(parentId) || "root".equals(parentId);
    }

    /**
     * 检查是否需要加密
     * @return true如果需要加密
     */
    public boolean requiresEncryption() {
        return isEncrypted != null && isEncrypted == 1;
    }

    /**
     * 检查是否有加密密码
     * @return true如果有加密密码
     */
    public boolean hasEncryptPassword() {
        return StringUtils.isNotBlank(encryptPassword);
    }

    /**
     * 获取文件扩展名
     * @return 文件扩展名，不包含点号
     */
    public String getFileExtension() {
        if (StringUtils.isBlank(fileName) || isDirectoryType()) {
            return "";
        }

        int lastDotIndex = fileName.lastIndexOf('.');
        return lastDotIndex > 0 ? fileName.substring(lastDotIndex + 1).toLowerCase() : "";
    }

    /**
     * 获取不包含扩展名的文件名
     * @return 不包含扩展名的文件名
     */
    public String getFileNameWithoutExtension() {
        if (StringUtils.isBlank(fileName)) {
            return "";
        }

        int lastDotIndex = fileName.lastIndexOf('.');
        return lastDotIndex > 0 ? fileName.substring(0, lastDotIndex) : fileName;
    }

    /**
     * 设置为目录类型
     */
    public void setAsDirectory() {
        this.isDirectory = true;
        this.fileType = null; // 目录没有文件类型
    }

    /**
     * 设置为文件类型
     */
    public void setAsFile() {
        this.isDirectory = false;
    }

    /**
     * 启用加密
     * @param password 加密密码
     */
    public void enableEncryption(String password) {
        this.isEncrypted = 1;
        this.encryptPassword = password;
    }

    /**
     * 禁用加密
     */
    public void disableEncryption() {
        this.isEncrypted = 0;
        this.encryptPassword = null;
    }

    /**
     * 验证DTO数据的完整性
     * @return true如果数据有效
     */
    public boolean isValid() {
        if (StringUtils.isBlank(userId) || StringUtils.isBlank(fileName)) {
            return false;
        }

        // 如果需要加密，必须有密码
        if (requiresEncryption() && !hasEncryptPassword()) {
            return false;
        }

        // 文件名不能包含非法字符
        String invalidChars = "\\/:*?\"<>|";
        for (char c : invalidChars.toCharArray()) {
            if (fileName.indexOf(c) >= 0) {
                return false;
            }
        }

        return true;
    }

    /**
     * 清理敏感信息（用于日志记录）
     * @return 清理后的DTO副本
     */
    public FileDTO sanitizeForLogging() {
        FileDTO sanitized = new FileDTO();
        sanitized.setId(this.id);
        sanitized.setUserId(this.userId);
        sanitized.setParentId(this.parentId);
        sanitized.setFileName(this.fileName);
        sanitized.setFileType(this.fileType);
        sanitized.setIsDirectory(this.isDirectory);
        sanitized.setIsEncrypted(this.isEncrypted);
        // 不复制加密密码
        return sanitized;
    }
}
